package com.yx.fsysserver.file.controller;

import com.yx.fsysserver.common.exception.ServiceException;
import com.yx.fsysserver.file.domain.FileInfo;
import com.yx.fsysserver.file.service.FileService;
import com.yx.fsysserver.file.vo.UploadResult;
import com.yx.lib.http.WebUtil;
import com.yx.lib.utils.FileInfoUtils;
import com.yx.lib.utils.file.PathUtil;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;

/**
 * 文件上传下载预览
 * Created by lichagnfeng on 2017/3/3.
 */
@RestController
@RequestMapping("/file")
public class FileController {
    private Logger log = LoggerFactory.getLogger(FileController.class);
    @Value("${file.upload.suffix}")
    private String suffixs;
    @Autowired
    private FileService fileService;


    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public String test(){
        return  "stee";
    }



    @RequestMapping(value = "/upload",method = RequestMethod.POST)
    public UploadResult upload(@RequestParam("file") MultipartFile multipartFile, HttpServletRequest request){

        if (multipartFile == null) {
            return new UploadResult(false,"读取失败！",null,null,0,"","","");
        }


        InputStream inputStream = null;

        try {
            //获取系统支持上传文件格式
            List<String> suffixList = Arrays.asList(suffixs.split(","));
            String fileName = multipartFile.getOriginalFilename();//获取文件名称
            inputStream = multipartFile.getInputStream();
            String suffix = FileInfoUtils.getFileSuffix(fileName);
            if(suffixList.contains(suffix)){
                if ("zip".equalsIgnoreCase(suffix)){
                    UploadResult result = this.fileService.uploadDirFile(inputStream,fileName);
                    return result;
                }else {
                    UploadResult result = this.fileService.uploadFile(inputStream, fileName);
                    return result;
                }
            }else{
                throw new ServiceException("上传文件格式系统不支持!");
            }

        } catch (IOException e) {
            log.error("",e);
        }
        return null;
    }

    /**
     * desc:  内部调用(yxppt)
     * date:
     * @author cuihao
     * @param fileName
     * @param request 从该对象读取二进制流图片
     * @return
     */
    @RequestMapping(value = "/innerUpload",method = RequestMethod.POST)
    public UploadResult upload(@RequestParam("fileName")String fileName, HttpServletRequest request) throws Exception{
        Assert.isTrue(!StringUtils.isEmpty(fileName),"文件名不能为空!");
        InputStream stream = request.getInputStream();
        UploadResult result = this.fileService.uploadFile(stream, fileName);
        return result;
    }

    /**
     * 上传压缩的目录，需要解压缩后存放
     * @param multipartFile
     * @param request
     * @return
     */
    @RequestMapping(value = "/uploadUnzip",method = RequestMethod.POST)
    public UploadResult uploadUnzip(@RequestParam("file") MultipartFile multipartFile, HttpServletRequest request){

        if (multipartFile == null) {
            return new UploadResult(false,"读取失败！",null,null,0,"","","");
        }


        InputStream inputStream = null;

        try {
            String fileName = multipartFile.getOriginalFilename();//获取文件名称
            inputStream = multipartFile.getInputStream();


            UploadResult result = this.fileService.uploadDirFile(inputStream,fileName);
            return result;

        } catch (IOException e) {
            log.error("",e);
        }
        return null;
    }

    @RequestMapping(value = "/down")
    public void download( String path, HttpServletRequest request, HttpServletResponse response) throws Exception {
        //path="/fsysserver2/file/read/other/2018-05-11/039998d6-5169-409b-a653-9c140f67dd74.doc";
        Example example=new Example(FileInfo.class);
        example.createCriteria().andEqualTo("path",path);
        List<FileInfo> fileList=this.fileService.selectByExample(example);
        if (null!=fileList && fileList.size()>0) {
            FileInfo fileInfo = fileList.get(0);
            path = path.substring("/fsysserver2/file/read/".length());
            InputStream fis = this.fileService.getInputStreamByPath(path);
                int len = 0;
                String filename= URLEncoder.encode(fileInfo.getSrcName(), "utf-8"); //解决中文文件名下载后乱码的问题
                if ("FF".equals(WebUtil.getBrowser(request))) {
                    // 针对火狐浏览器处理方式不一样了
                    filename = new String((fileInfo.getSrcName()).getBytes("UTF-8"), "iso-8859-1");
                }
                byte[] b = new byte[2048];
                response.setCharacterEncoding("utf-8");
                response.setHeader("Content-disposition","attachment;filename=\"" + filename + "\"");
                //获取响应报文输出流对象
                ServletOutputStream out =response.getOutputStream();
                //输出
                while ((len = fis.read(b)) > 0){
                    out.write(b, 0, len);
                }
                out.flush();
                out.close();
        }

    }


    /**
     * 预览
     * @param req
     * @param resp
     */
    @RequestMapping(value = "/read/**")
    public void read(HttpServletRequest req, HttpServletResponse resp) {
        String path = req.getServletPath();
        path = path.substring("/file/read/".length());
//        if (path.contains("webhtml")){
//            String url = req.getScheme()+"://"+ req.getServerName()+":"+req.getServerPort()+"/";//+request.getRequestURI();
//            try {
//                resp.sendRedirect(url+path);
//                return;
//            } catch (IOException e) {
//                log.error("", e);
//            }
//        }
        log.debug("path:"+path);

        String suffix = FileInfoUtils.getFileSuffix(path);
        InputStream inputStream = null;
        try {
            if (suffix.equalsIgnoreCase("mp4")){//如果是视频
                //FileInfo fileInfo = this.fileService.getFileInfoByPath(path);
                long fileLen = this.fileService.getFileLength(path);
                inputStream = this.fileService.getInputStreamByPath(path);
                if (inputStream == null) {
                    resp.setStatus(404);
                    return;
                }
                this.readFromInputStream(inputStream,req,resp,fileLen);
            }else {//其他
                OutputStream out = resp.getOutputStream();
                inputStream = this.fileService.getInputStreamByPath(path);
                if (inputStream == null) {
                    resp.setStatus(404);
                    return;
                }
                IOUtils.copy(inputStream,out);
            }
        }catch (Exception e){
            throw new ServiceException("读取失败",e);
        }finally {
            if (inputStream!=null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("",e);
                }
            }
        }


    }


    private void readFromInputStream(InputStream in,HttpServletRequest req, HttpServletResponse resp,long fileLen){
        OutputStream out = null;
        try {
            String rangeStr = req.getHeader("Range");
            //log.info("22222222222222");
            if (rangeStr != null) {
                resp.setHeader("Accept-Ranges", "bytes");
                //resp.setHeader("ETag", "W/\"9528106-1480406389802\"");
                //resp.setHeader("Last-Modified","Tue, 29 Nov 2016 07:59:49 GMT");
                resp.setHeader("Content-type", "video/mp4");
                if (fileLen < Integer.MAX_VALUE) {
                    resp.setContentLength((int) fileLen);
                } else {
                    // Set the content-length as String to be able to use a
                    // long
                    resp.setHeader("content-length","" + fileLen);
                }

                Range currentRange = new Range();
                currentRange.length = fileLen;
                String rangeHeader = req.getHeader("Range");
                //log.debug("rangeHeader:"+rangeHeader);
                rangeHeader = rangeHeader.substring(6);
                StringTokenizer commaTokenizer = new StringTokenizer(rangeHeader, ",");
                commaTokenizer.hasMoreTokens();
                String rangeDefinition = commaTokenizer.nextToken().trim();
                int dashPos = rangeDefinition.indexOf('-');
                //log.info("333333333333333333333333");
                if (dashPos == 0) {
                    //log.info("444444444444444444");
                    try {
                        long offset = Long.parseLong(rangeDefinition);
                        currentRange.start = fileLen + offset;
                        currentRange.end = fileLen - 1;
                    } catch (NumberFormatException e) {
                        log.error("",e);
                    }

                } else {
                    //log.info("55555555555555555555");
                    try {
                        currentRange.start = Long.parseLong
                                (rangeDefinition.substring(0, dashPos));
                        if (dashPos < rangeDefinition.length() - 1)
                            currentRange.end = Long.parseLong
                                    (rangeDefinition.substring
                                            (dashPos + 1, rangeDefinition.length()));
                        else
                            currentRange.end = fileLen - 1;
                    } catch (NumberFormatException e) {
                        log.error("",e);
                    }

                }
                resp.setStatus(206);
                resp.setContentType("video/mp4");

                Range range = currentRange;
                resp.addHeader("Content-Range", "bytes "
                        + range.start
                        + "-" + range.end + "/"
                        + range.length);
                long length = range.end - range.start + 1;
                if (length < Integer.MAX_VALUE) {
                    resp.setContentLength((int) length);
                } else {
                    // Set the content-length as String to be able to use a long
                    resp.setHeader("content-length", "" + length);
                }
                //resp.setBufferSize(2048);

                out = resp.getOutputStream();
                copyRange(in, out, range.start, range.end);
                //log.info("8888888888888");

            } else {
                out = resp.getOutputStream();
                IOUtils.copy(in, out);
            }
        }catch (IOException e) {
            log.error("",e);
        } catch (Exception e) {
            log.error("",e);
        }finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error("",e);
                }
            }
        }

    }

    protected static class Range {

        public long start;
        public long end;
        public long length;

        /**
         * Validate range.
         */
        public boolean validate() {
            if (end >= length)
                end = length - 1;
            return (start >= 0) && (end >= 0) && (start <= end) && (length > 0);
        }
    }

    protected IOException copyRange(InputStream istream,
                                    OutputStream ostream,
                                    long start, long end) {
        long skipped = 0;
        try {
            skipped = istream.skip(start);
        } catch (IOException e) {
            return e;
        }
        if (skipped < start) {
            return new IOException("start:"+start+",skip:"+skipped);
        }

        IOException exception = null;
        long bytesToRead = end - start + 1;

        byte buffer[] = new byte[2048];
        int len = buffer.length;
        //while ( (bytesToRead > 0) && (len >= buffer.length)) {
        while ( bytesToRead > 0&& len>0) {
            try {
                len = istream.read(buffer);
                if (bytesToRead >= len) {
                    ostream.write(buffer, 0, len);
                    bytesToRead -= len;
                } else {
                    ostream.write(buffer, 0, (int) bytesToRead);
                    bytesToRead = 0;
                }
            } catch (IOException e) {
                exception = e;
                len = -1;
            }
            /*if (len < buffer.length)
                break;*/
        }
        return exception;

    }



}
